package com.pro.common.cursor.sync.service;

import com.pro.common.api.cursor.sync.enums.EnumCursorValueType;
import com.pro.framework.api.enums.ITaskCursorKey;
import com.pro.common.api.cursor.sync.model.dto.BatchResult;
import com.pro.common.api.cursor.sync.service.ICursorSyncHandler;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;

@Service
@AllArgsConstructor
@Slf4j
public class CursorSyncExecutor {

    private SysTaskCursorService sysTaskCursorService;

    public <T, C extends Comparable<? super C>> void execute(ICursorSyncHandler<T, C> handler) {
        this.execute(handler, null);
    }

    public <T, C extends Comparable<? super C>> void execute(ICursorSyncHandler<T, C> handler, C end) {
        ITaskCursorKey taskKey = handler.getCursorKey();
        C cursor = getCursor(taskKey, handler.getCursorClass(), handler.getDefaultCursor());
        int total = 0;

        while (true) {
            BatchResult<C> result = processBatch(handler, taskKey, cursor, end);
            if (!result.success()) break;
            cursor = result.newCursor();
            total += result.count();
        }

        log.info("[{}] 全量执行完成，共处理 {} 条，最终游标={}", handler.getCursorKey(), total, cursor);
    }

    public <T, C extends Comparable<? super C>> void executeOnce(ICursorSyncHandler<T, C> handler) {
        this.executeOnce(handler, null);
    }

    public <T, C extends Comparable<? super C>> void executeOnce(ICursorSyncHandler<T, C> handler, C end) {
        ITaskCursorKey taskKey = handler.getCursorKey();
        C cursor = getCursor(taskKey, handler.getCursorClass(), handler.getDefaultCursor());

        BatchResult<C> result = processBatch(handler, taskKey, cursor, end);
        if (result.success()) {
            log.info("[{}] 单次处理 {} 条，游标从 {} 更新为 {}", handler.getCursorKey(), result.count(), cursor, result.newCursor());
        }
    }

    private <T, C extends Comparable<? super C>> BatchResult<C> processBatch(ICursorSyncHandler<T, C> handler, ITaskCursorKey taskKey, C cursor, C end) {
        List<T> dataList = handler.fetchData(cursor, handler.getBatchSize(), end);
        if (dataList.isEmpty()) {
            log.info("[{}] 无新数据，cursor={}", handler.getCursorKey(), cursor);
            return BatchResult.noData();
        }

        handler.process(dataList);

        Comparator<C> comparator = handler.getCursorAscending() ? Comparator.naturalOrder() : Comparator.reverseOrder();

        C newCursor = dataList.stream()
                .map(handler::extractCursorValue)
                .max(comparator)
                .orElse(cursor);
        if (end != null) {
            if (handler.getCursorAscending()) {
                // 正序，不能超过 end
                if (comparator.compare(newCursor, end) > 0) {
                    newCursor = end;
                }
            } else {
                // 倒序，不能小于 end
                if (comparator.compare(newCursor, end) < 0) {
                    newCursor = end;
                }
            }
        }
        // 判断是否推进，利用 comparator.compare(newCursor, cursor) > 0
        if (comparator.compare(newCursor, cursor) <= 0) {
            log.warn("[{}] 游标未推进，cursor={}", handler.getCursorKey(), cursor);
            return BatchResult.noProgress();
        }

        updateCursor(taskKey, newCursor, handler.getCursorClass());
        return BatchResult.success(newCursor, dataList.size());
    }

    @SuppressWarnings("unchecked")
    private <C> C getCursor(ITaskCursorKey key, Class<C> clazz, C defaultValue) {
        Object value;

        if (clazz == Long.class) {
            value = sysTaskCursorService.getLongCursor(key, (Long) defaultValue);
        } else if (clazz == LocalDateTime.class) {
            value = sysTaskCursorService.getTimeCursor(key, (LocalDateTime) defaultValue);
        } else if (clazz == String.class) {
            String raw = sysTaskCursorService.getCursorValue(key);
            value = (raw != null) ? raw : defaultValue;
        } else {
            throw new IllegalArgumentException("不支持的游标类型: " + clazz.getName());
        }

        return (C) value;
    }

    @SuppressWarnings("unchecked")
    private <C> void updateCursor(ITaskCursorKey key, C cursor, Class<C> clazz) {
        String remark = "自动更新游标";

        if (cursor == null) {
            log.warn("尝试更新游标为空: [{}]", key);
            return;
        }

        if (clazz == Long.class) {
            sysTaskCursorService.updateLongCursor(key, (Long) cursor, remark);
        } else if (clazz == LocalDateTime.class) {
            sysTaskCursorService.updateTimeCursor(key, (LocalDateTime) cursor, remark);
        } else if (clazz == String.class) {
            sysTaskCursorService.upsertCursor(key, (String) cursor, remark, EnumCursorValueType.STRING);
        } else {
            throw new IllegalArgumentException("不支持的游标类型: " + clazz.getName());
        }
    }

}
